package be.dch.objectprops.parser;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Set;

import org.apache.log4j.Logger;

import be.dch.objectprops.ParserFinder;
import be.dch.objectprops.collector.Collector;
import be.dch.objectprops.impl.ObjectUtil;
import be.dch.util.StringUtils;

import com.google.inject.Inject;

public class CollectionParser implements Parser {

    private static final Logger LOG = Logger.getLogger(CollectionParser.class);
    @Inject
    private Collector props;

    @Inject
    private ParserFinder finder;

    private static final String PROP_SEPA = ".";
    private static final String PROP_TYPE = "type";
    private static final String PROP_VALUE = "value";
    private static final String PROP_VALUE_TYPE = "valueType";

    /*
     * (non-Javadoc)
     * 
     * @see be.dch.objectprops.parser.Parser#handleAsWriter(java.lang.Object)
     */
    
    public boolean handleAsWriter(final Object result) {
	if (result instanceof Collection) {
	    return true;
	}
	return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * be.dch.objectprops.parser.Parser#handleAsReader(java.lang.reflect.Field)
     */
    
    public boolean handleAsReader(final Field field) {
	CollectionParser.LOG.debug("Investigating of object can be handled");
	if (field == null) {
	    return false;
	}
	return field.getType().getCanonicalName().equals(Set.class.getCanonicalName());
    }

    /*
     * (non-Javadoc)
     * 
     * @see be.dch.objectprops.parser.Parser#write(java.lang.Object,
     * java.lang.StringBuilder, be.dch.objectprops.impl.ObjectWriter,
     * be.dch.objectprops.collector.Collector)
     */
    
    public void write(final Object result, final StringBuilder key) {
	final int initialLength = key.length();
	final Collection<?> setResult = (Collection<?>) result;
	final int keyLength = key.toString().length();
	key.append(CollectionParser.PROP_SEPA);
	key.append("type");
	this.props.setProperty(key.toString(), result.getClass().getCanonicalName());
	int j = 0;
	for (final Object item : setResult) {
	    key.setLength(keyLength);
	    key.append(CollectionParser.PROP_SEPA);
	    key.append(j);
	    key.append(CollectionParser.PROP_SEPA);
	    key.append(CollectionParser.PROP_VALUE);
	    this.finder.write(item, key);
	    key.setLength(keyLength);
	    key.append(CollectionParser.PROP_SEPA);
	    key.append(j);
	    key.append(CollectionParser.PROP_SEPA);
	    key.append(CollectionParser.PROP_VALUE_TYPE);
	    this.props.setProperty(key.toString(), item.getClass().getCanonicalName());
	    j++;

	}
	key.setLength(initialLength);
    }

    /*
     * (non-Javadoc)
     * 
     * @see be.dch.objectprops.parser.Parser#read(java.lang.StringBuilder,
     * java.lang.reflect.Field, java.lang.Object,
     * be.dch.objectprops.impl.ObjectReader,
     * be.dch.objectprops.collector.Collector)
     */
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void read(final StringBuilder key, final Field collection, final Object result) {
	CollectionParser.LOG.debug("Analysing collection with key: " + key.toString());
	final int initialLength = key.length();
	try {
	    key.append(CollectionParser.PROP_SEPA);
	    key.append(CollectionParser.PROP_TYPE);
	    final String clazz = this.props.getProperty(key.toString());
	    if (!StringUtils.isEmpty(clazz)) {
		CollectionParser.LOG.debug("Create resultSet of type: " + clazz);
		final Collection resultSet = (Collection<?>) ObjectUtil.newInstance(clazz);
		CollectionParser.LOG.debug(resultSet);
		int j = 0;
		key.setLength(initialLength);
		key.append(CollectionParser.PROP_SEPA);
		key.append(j);
		while (this.props.startWithKey(key.toString())) {
		    key.setLength(initialLength);
		    key.append(CollectionParser.PROP_SEPA);
		    key.append(j);
		    key.append(CollectionParser.PROP_SEPA);
		    key.append(CollectionParser.PROP_VALUE);
		    final String value = key.toString();
		    key.setLength(initialLength);
		    key.append(CollectionParser.PROP_SEPA);
		    key.append(j);
		    key.append(CollectionParser.PROP_SEPA);
		    key.append(CollectionParser.PROP_VALUE_TYPE);
		    final String valueType = this.props.getProperty(key.toString());
		    Object valueObject = ObjectUtil.newInstance(valueType);
		    valueObject = this.finder.read(new StringBuilder(value), valueObject);
		    CollectionParser.LOG.debug("Adding value " + valueObject.toString() + " to collection.");
		    resultSet.add(valueObject);
		    j++;
		    key.setLength(initialLength);
		    key.append(CollectionParser.PROP_SEPA);
		    key.append(j);
		}
		collection.set(result, resultSet);
	    }
	} catch (final IllegalAccessException e) {
	    CollectionParser.LOG.error(e);
	}
	key.setLength(initialLength);
    }

    
    public Object read(final StringBuilder key, final Object result) {
	return null;
    }
    
    protected void setProps(Collector props) {
	this.props = props;
    }
    
    protected void setFinder(ParserFinder finder) {
	this.finder = finder;
    }

}
